import json
import os
import sys
import random
import psutil
import pygame
import requests
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *


class DesktopPet(QWidget):
    def __init__(self, parent=None, **kwargs):
        super(DesktopPet, self).__init__(parent)
        # 窗体初始化
        self.init()
        # 托盘化初始
        self.initPall()
        # 宠物静态gif图加载
        self.initPetImage()
        # 宠物正常待机，实现随机切换动作
        self.petNormalAction()
        self.initNormal()

    # 在类中添加这两个QTimer对象
    def initNormal(self):
        # 读取json文件（注意修正文件模式为'r'）
        with open('time.json', 'rb') as f:
            times = json.load(f)
            self.sport_interval = times.get("运动时间提醒")
            self.laptop_interval = times.get("电脑健康时间提醒")

        # 创建运动提醒定时器
        self.sport_timer = QTimer()
        self.sport_timer.timeout.connect(self.sport_reminder)
        self.sport_timer.start(self.sport_interval * 1000)  # 转换为毫秒

        # 创建电脑提醒定时器
        self.laptop_timer = QTimer()
        self.laptop_timer.timeout.connect(self.laptop_reminder)
        self.laptop_timer.start(self.laptop_interval * 1000)

        #创建课表提醒的定时器
        self.class_reminder_timer = QTimer()
        self.class_reminder_timer.timeout.connect(self.check_class_reminder)
        self.class_reminder_timer.start(5000)  # 每分钟检查一次

    def check_class_reminder(self):
        # 读取课程表
        with open('class_schedule.json', 'r', encoding='utf-8') as f:
            schedule = json.load(f)

        # 获取当前时间和日期
        now = QDateTime.currentDateTime()
        current_time = now.time().toString("HH:mm")
        current_date = now.date()

        # 计算当前是单周还是双周
        start_date = QDate.fromString(schedule["start_date"], "yyyy-MM-dd")
        days_diff = start_date.daysTo(current_date)
        week_number = (days_diff // 7) + 1
        is_single_week = (week_number % 2 == 1) if schedule["current_type"] == "单周" else (week_number % 2 == 0)

        # 获取今天的课程
        today = now.toString("ddd")
        if is_single_week:
            classes = schedule["单周"].get(today, [])
        else:
            classes = schedule["双周"].get(today, [])

        # 检查每节课是否需要提醒
        for i, class_name in enumerate(classes):
            if class_name:  # 如果有课
                class_time = schedule["上课时间"][i]
                class_time = QTime.fromString(class_time, "HH:mm")
                reminder_time = class_time.addSecs(-30 * 60)  # 提前半小时提醒

                if QTime.fromString(current_time, "HH:mm") == reminder_time:
                    self.condition = 5  # 课程提醒状态
                    self.randomAct()
                    QTimer.singleShot(100, lambda: self.speaking(f"半小时后有 {class_name} 课，记得准备哦！", 10000))
                    #播放声音提醒
                    self.play_mp3("上课提醒.mp3")

    def play_mp3(self,file_path):
        pygame.mixer.init()
        pygame.mixer.music.load(file_path)
        pygame.mixer.music.play()
        pygame.time.Clock().tick(10)



    def sport_reminder(self):
        # 读取最新配置
        with open('time.json', 'rb') as f:
            self.sport_interval = json.load(f).get("运动时间提醒")

        # 重启定时器
        self.sport_timer.stop()
        self.sport_timer.setInterval(self.sport_interval * 1000)
        self.sport_timer.start()

        # 执行提醒操作
        self.condition = 3
        self.randomAct()
        # 延迟100ms确保动画加载完成再显示对话框
        QTimer.singleShot(100, lambda: self.speaking("运动时间到，跟小新一起来运动", 10000))  # 时间改为10000与动画同步

    def laptop_reminder(self):
        # 读取最新配置
        with open('time.json', 'rb') as f:
            self.laptop_interval = json.load(f).get("电脑健康时间提醒")

        # 重启定时器
        self.laptop_timer.stop()
        self.laptop_timer.setInterval(self.laptop_interval * 1000)
        self.laptop_timer.start()

        # 执行提醒操作
        self.condition = 4
        self.randomAct()
        # 延迟100ms确保动画加载完成再显示对话框
        QTimer.singleShot(100, lambda: self.speaking("电脑使用这么长时间了，该和小新一起休息会儿", 10000))

    # 窗体初始化
    def init(self):
        # 初始化
        # 设置窗口属性:窗口无标题栏且固定在最前面
        # FrameWindowHint:无边框窗口
        # WindowStaysOnTopHint: 窗口总显示在最上面
        # SubWindow: 新窗口部件是一个子窗口，而无论窗口部件是否有父窗口部件
        # https://blog.csdn.net/kaida1234/article/details/79863146
        self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.SubWindow)
        # setAutoFillBackground(True)表示的是自动填充背景,False为透明背景
        self.setAutoFillBackground(False)
        # 窗口透明，窗体空间不透明
        self.setAttribute(Qt.WA_TranslucentBackground, True)
        # 重绘组件、刷新
        self.repaint()


    # 托盘化设置初始化
    def initPall(self):
        # 导入准备在托盘化显示上使用的图标
        icons = os.path.join('tigerIcon.jpg')
        # 设置右键显示最小化的菜单项
        # 菜单项退出，点击后调用quit函数
        quit_action = QAction('退出', self, triggered=self.quit)
        # 设置这个点击选项的图片
        quit_action.setIcon(QIcon(icons))
        # 菜单项显示，点击后调用toggleShowHide函数
        #初始化显示宠物的判断值
        self.show_pet=True
        # 菜单项显示隐藏
        self.show_action = QAction(u'隐藏', self, triggered=self.toggleShowHide)  # 切换显示/隐藏
        # 菜单项天气预报
        self.weatherForecast_action=QAction(u"天气预报",self,triggered=self.weatherForecastRight)
        #菜单设置
        self.setting_action=QAction(u"设置",self,triggered=self.showSettingsWindow)
        # 新建一个菜单项控件
        self.tray_icon_menu = QMenu(self)
        # 在菜单栏添加一个无子菜单的菜单项‘退出’
        self.tray_icon_menu.addAction(quit_action)
        # 在菜单栏添加一个无子菜单的菜单项‘显示’
        self.tray_icon_menu.addAction(self.show_action)
        # 在菜单栏添加一个无子菜单的菜单项‘天气预报’
        self.tray_icon_menu.addAction(self.weatherForecast_action)
        # 添加电脑信息实时显示菜单项
        self.system_info_action = QAction(u'电脑信息实时显示', self, triggered=self.updateSystemInfo)
        self.tray_icon_menu.addAction(self.system_info_action)
        # 在菜单栏添加一个无子菜单的菜单项‘设置’
        self.tray_icon_menu.addAction(self.setting_action)
        # QSystemTrayIcon类为应用程序在系统托盘中提供一个图标
        self.tray_icon = QSystemTrayIcon(self)
        # 设置托盘化图标
        self.tray_icon.setIcon(QIcon(icons))
        # 设置托盘化菜单项
        self.tray_icon.setContextMenu(self.tray_icon_menu)
        # 展示
        self.tray_icon.show()

    # 宠物静态gif图加载
    def initPetImage(self):
        # 对话框定义
        self.talkLabel = QLabel(self)
        # 对话框样式设计
        self.talkLabel.setStyleSheet("font:15pt '楷体';border-width: 1px;color:blue;")
        # 定义显示图片部分
        self.image = QLabel(self)
        # QMovie是一个可以存放动态视频的类，一般是配合QLabel使用的,可以用来存放GIF动态图
        self.movie = QMovie("normal/normal1.gif")
        # 设置标签大小
        self.movie.setScaledSize(QSize(200, 200))
        # 将Qmovie在定义的image中显示
        self.image.setMovie(self.movie)
        self.movie.start()
        #自动适应屏幕大小
        screen_geometry = QDesktopWidget().screenGeometry()
        self.resize(int(screen_geometry.width() * 0.5), int(screen_geometry.height() * 0.5))        # 调用自定义的randomPosition，会使得宠物出现位置随机
        self.randomPosition()
        # 展示
        self.show()
        # https://new.qq.com/rain/a/20211014a002rs00
        # 将宠物正常待机状态的动图放入pet1中
        self.pet1 = []
        for i in os.listdir("normal"):
            self.pet1.append("normal/" + i)
        # 将宠物多云，阴天状态的动图放入petCloudy中
        self.petCloudy=[]
        for i in os.listdir("weather/cloudy"):
            self.petCloudy.append("weather/cloudy/"+i)
        #将宠物霾状态的动图放入petHaze中
        self.petHaze=[]
        for i in os.listdir("weather/haze"):
            self.petHaze.append("weather/haze/"+i)
        #将宠物下雨状态的动图放入petRainy中
        self.petRainy=[]
        for i in os.listdir("weather/rainy"):
            self.petRainy.append("weather/rainy/"+i)
        #将宠物晴天状态的动图放入petSunny中
        self.petSunny=[]
        for i in os.listdir("weather/sunny"):
            self.petSunny.append("weather/sunny/"+i)

        self.petSport=[]
        for i in os.listdir("reminder/sport"):
            self.petSport.append("reminder/sport/"+i)

        self.petLaptop=[]
        for i in os.listdir("reminder/laptop"):
            self.petLaptop.append("reminder/laptop/"+i)

        self.petclass = []
        for i in os.listdir("reminder/class"):
            self.petLaptop.append("reminder/class/" + i)
        # 将宠物正常待机状态的对话放入pet2中
        self.dialog = []
        # 读取目录下dialog文件
        with open("dialog.txt", "r",encoding="utf-8") as f:
            text = f.read()
            # 以\n 即换行符为分隔符，分割放进dialog中
            self.dialog = text.split("\n")

    # 宠物正常待机动作
    def petNormalAction(self):
        #初始化动作和对话
        self.condition=0
        self.talk_condition = 0

        # 每隔一段时间做个动作
        if self.condition==0:
            # 定时器设置
            self.timer = QTimer()
            # 时间到了自动执行
            self.timer.timeout.connect(self.randomAct)
            # 动作时间切换设置
            self.timer.start(30000)

        # 每隔一段时间切换对话
        if self.talk_condition==0:
            self.talkTimer = QTimer()
            self.talkTimer.timeout.connect(self.talk)
            self.talkTimer.start(30000)
            # 对话状态设置为常态
        # 宠物对话框
        self.talk()

    def randomAct(self):
        # 定义一个内部函数来设置动画
        def set_animation(gif_list, condition=0, timer_duration=None):
            self.movie = QMovie(random.choice(gif_list))
            self.movie.setScaledSize(QSize(200, 200))
            self.image.setMovie(self.movie)
            self.movie.start()  # 确保立即开始播放
            self.condition = condition
            if timer_duration:
                # 修改为只停止当前状态动画的定时器
                if hasattr(self, 'action_timer'):
                    self.action_timer.stop()
                self.action_timer = QTimer()
                self.action_timer.singleShot(timer_duration, self.resetToNormal)
        # 根据宠物状态选择不同的动作
        #self.condition=0是正常待机，self.condition=1是点击到，self.condition=2是天气预报
        if self.condition == 0:
            set_animation(self.pet1)
        elif self.condition == 1:
            set_animation(["./click/click.gif"], timer_duration=1000)
        elif self.condition == 2:
            city, time, high, low, weather, tip = self.weatherForecast()
            if "晴" in weather:
                set_animation(self.petSunny, timer_duration=5000)
            elif "雨" in weather:
                set_animation(self.petRainy, timer_duration=5000)
            elif "霾" in weather:
                set_animation(self.petHaze, timer_duration=5000)
            elif "多云" in weather or "阴" in weather:
                set_animation(self.petCloudy, timer_duration=5000)
        elif self.condition==3:
            set_animation(self.petSport, timer_duration=10000)
        elif self.condition==4:
            set_animation(self.petLaptop,timer_duration=10000)
        elif self.condition==5:
            set_animation(self.petLaptop,timer_duration=10000)

    def speaking(self,textdata,singleShotTime):
        # 移除原来的self.talk_condition设置
        text = textdata
        self.talkLabel.setText(text)
        # 设置样式
        self.talkLabel.setStyleSheet(
            "font: bold 15pt '楷体';"  # 字体大小和样式
            "color: black;"  # 文字颜色
            "background-color: rgba(255, 255, 255, 200);"  # 背景颜色，带透明度
            "border: 2px solid black;"  # 边框
            "border-radius: 10px;"  # 圆角
            "padding: 5px;"  # 内边距
        )
        # 启用自动换行
        self.talkLabel.setWordWrap(True)
        # 根据内容自适应大小
        self.talkLabel.adjustSize()
        self.talk_condition = 0
        # 设置与动画同步的定时器
        self.talk_timer = QTimer()
        self.talk_timer.singleShot(singleShotTime, self.talk)

    def resetToNormal(self):
        """重置为正常状态"""
        self.condition = 0
        self.randomAct()

    # 宠物对话框行为处理
    def talk(self):
        if not self.talk_condition:
            # talk_condition为0则选取加载在dialog中的语句
            text = random.choice(self.dialog)
            # 每 10 个字换行
            text = '\n'.join([text[i:i + 10] for i in range(0, len(text), 10)])
            self.talkLabel.setText(text)
            # 设置样式
            self.talkLabel.setStyleSheet(
                "font: bold 15pt '楷体';"  # 字体大小和样式
                "color: black;"  # 文字颜色
                "background-color: rgba(255, 255, 255, 200);"  # 背景颜色，带透明度
                "border: 2px solid black;"  # 边框
                "border-radius: 10px;"  # 圆角
                "padding: 5px;"  # 内边距
            )
            # 启用自动换行
            self.talkLabel.setWordWrap(True)
            # 根据内容自适应大小
            self.talkLabel.adjustSize()
        elif self.talk_condition==1:
            # talk_condition为1显示为别点我
            self.talkLabel.setText("别点我")
            self.talkLabel.setStyleSheet(
                "font: bold 15pt '楷体';"  # 字体大小和样式
                "color: black;"  # 文字颜色
                "background-color: rgba(255, 255, 255, 200);"  # 背景颜色，带透明度
                "border: 2px solid black;"  # 边框
                "border-radius: 10px;"  # 圆角
                "padding: 5px;"  # 内边距
            )
            # 启用自动换行
            self.talkLabel.setWordWrap(True)
            self.talkLabel.adjustSize()
            # 设置为正常状态
            self.talk_condition = 0
            QTimer.singleShot(1000,self.passClickTalk)

        # 调整对话框位置，使其显示在桌宠头上
        self.adjustTalkLabelPosition()

    #因为点击事件和点击组合的事件冲突，另开的方法
    def passClickTalk(self):
        if self.talk_condition==2:
            if self.weatherForecast()==None:
                self.speaking("小新找不到你的城市哦",5000)
            elif self.weatherForecast()=="exit":
                self.speaking("没有网络欸！找小新给你连接WiFi哦",5000)
            else:
                city, time, high, low, weather, tip = self.weatherForecast()
                self.speaking(city + "\n" + time + "\n" + high + "\t" + low + "\n" + weather + "\n" + tip, 5000)
            self.talk_condition = 0
        elif self.talk_condition == 3:
            cpu, memory, network= self.computerInformation()
            self.speaking(cpu + "\n" + memory + "\n" + network, 5000)
            self.talk_condition = 0
        else:
            self.talk()


    def adjustTalkLabelPosition(self):

        # 获取桌宠的位置和大小
        pet_geometry = self.image.geometry()
        # 获取对话框的大小
        dialog_width = self.talkLabel.width()
        dialog_height = self.talkLabel.height()
        # 计算对话框的位置（居中显示在桌宠头上）
        dialog_x = pet_geometry.x() + (pet_geometry.width() - dialog_width) // 2
        dialog_y = pet_geometry.y() - dialog_height - 10  # 10 是对话框与桌宠的间距
        # 确保对话框不会超出屏幕
        screen_geometry = QDesktopWidget().screenGeometry()
        if dialog_x < 0:
            dialog_x = 0
        if dialog_y < 0:
            dialog_y = 0
        if dialog_x + dialog_width > screen_geometry.width():
            dialog_x = screen_geometry.width() - dialog_width
        if dialog_y + dialog_height > screen_geometry.height():
            dialog_y = screen_geometry.height() - dialog_height
        # 移动对话框到计算的位置
        self.talkLabel.move(dialog_x, dialog_y+200)

    # 退出操作，关闭程序
    def quit(self):
        self.close()
        sys.exit()

    #天气预报功能
    def weatherForecast(self):
        url = 'http://t.weather.sojson.com/api/weather/city/'
        # 读取json文件
        f = open('city.json', 'rb')
        # 使用json模块的load方法加载json数据，返回一个字典
        cities = json.load(f)
        self.city =cities.get("所在城市")
        # 通过城市的中文获取城市代码
        cityCode = cities.get(self.city)
        if cityCode==None:
            return None
        try:
            # 网络请求，传入请求api+城市代码
            response = requests.get(url + cityCode)
        except:
            return "exit"
        # 将数据以json形式返回，这个d就是返回的json数据
        data = response.json()
        # 当返回状态码为200，输出天气状况
        if (data['status'] == 200):
            city="城市："+data["cityInfo"]["city"]
            time=("时间："+data["data"]["forecast"][0]["week"])
            high=data["data"]["forecast"][0]["high"]
            low=data["data"]["forecast"][0]["low"]
            weather=("天气："+data["data"]["forecast"][0]["type"])
            tip="小新："+data["data"]["forecast"][0]["notice"]
            return city,time,high,low,weather,tip

    def computerInformation(self): # 获取计算机信息
            cpu_usage = psutil.cpu_percent(interval=1)
            memory_usage = psutil.virtual_memory().percent
            network_speed = psutil.net_io_counters().bytes_sent + psutil.net_io_counters().bytes_recv
            network_speed_mb = network_speed / 1024 / (1024 * 60 * 60)
            cpu = "CPU使用率：" + str(cpu_usage) + "%"
            memory = "内存使用率：" + str(memory_usage) + "%"
            network = "网络速度：" + str(network_speed_mb) + "MB/s"
            return cpu, memory, network

    # 切换显示/隐藏宠物
    def toggleShowHide(self):
        self.show_pet = not self.show_pet
        self.show_action.setText(u"显示" if not self.show_pet else u"隐藏")
        self.setWindowOpacity(1 if self.show_pet else 0)

    # 宠物随机位置
    def randomPosition(self):
        screen_geo = QDesktopWidget().screenGeometry()
        pet_geo = self.geometry()
        width = (screen_geo.width() - pet_geo.width()) * random.random()
        height = (screen_geo.height() - pet_geo.height()) * random.random()
        self.move(int(width), int(height))

    # 鼠标左键按下时, 宠物将和鼠标位置绑定
    def mousePressEvent(self, event):
        # 记录鼠标点击状态
        self.is_mouse_pressed = True
        # 更改宠物状态为点击
        self.condition = 1
        # 更改宠物对话状态
        self.talk_condition = 1
        # 即可调用对话状态改变
        self.talk()
        # 即刻加载宠物点击动画
        self.randomAct()
        if event.button() == Qt.LeftButton:
            self.is_follow_mouse = True
        # globalPos() 事件触发点相对于桌面的位置
        # pos() 程序相对于桌面左上角的位置，实际是窗口的左上角坐标
        self.mouse_drag_pos = event.globalPos() - self.pos()
        event.accept()
        # 拖动时鼠标图形的设置
        self.setCursor(QCursor(Qt.OpenHandCursor))
    #天气预报判断
    def keyPressEvent(self, event):
        # 判断是否按下了 W 键
        if event.key() == Qt.Key_W and self.is_mouse_pressed:
            # 设置 talk_condition 为 2
            self.talk_condition = 2
            # 触发相应动作
            self.talk()
        # 判断是否按下了 C键和I键
        elif event.key() == Qt.Key_C and self.is_mouse_pressed:
            #设置 talk_condition 为 3
            self.talk_condition = 3
            # 触发相应动作
            self.talk()
        # 调用父类的 keyPressEvent
        super().keyPressEvent(event)

    # 鼠标移动时调用，实现宠物随鼠标移动
    def mouseMoveEvent(self, event):
        # 如果鼠标左键按下，且处于绑定状态
        if Qt.LeftButton and self.is_follow_mouse:
            # 宠物随鼠标进行移动
            self.move(event.globalPos() - self.mouse_drag_pos)
        event.accept()

    # 鼠标释放调用，取消绑定
    def mouseReleaseEvent(self, event):
        self.is_follow_mouse = False
        # 鼠标图形设置为箭头
        self.setCursor(QCursor(Qt.ArrowCursor))

    # 鼠标移进时调用
    def enterEvent(self, event):
        # 设置鼠标形状 Qt.ClosedHandCursor   非指向手
        self.setCursor(Qt.ClosedHandCursor)

    #天气预报菜单中的显示方法
    def weatherForecastRight(self):
        self.talk_condition=2
        self.condition=2
        self.randomAct()
        self.passClickTalk()
    # 宠物右键点击交互
    def contextMenuEvent(self, event):
        # 定义菜单
        menu = QMenu(self)
        # 定义菜单项
        quitAction = menu.addAction("退出")
        hide = menu.addAction("隐藏")
        weatherForecast = menu.addAction("天气预报")
        computerInformationForecast = menu.addAction("电脑信息实时显示")
        settingAction = menu.addAction("设置")

        # 使用exec_()方法显示菜单。从鼠标右键事件对象中获得当前坐标。mapToGlobal()方法把当前组件的相对坐标转换为窗口（window）的绝对坐标。
        action = menu.exec_(self.mapToGlobal(event.pos()))
        # 点击事件为退出
        if action == quitAction:
            qApp.quit()
        # 点击事件为隐藏
        if action == hide:
            self.toggleShowHide()
        #点击事件为天气预报
        if action==weatherForecast:
            self.weatherForecastRight()
        #点击事件为电脑信息实时显示
        if action==computerInformationForecast:
            self.computerInformationForecastRight()
        if action==settingAction:
            self.showSettingsWindow()
    #电脑信息菜单中的显示方法
    def computerInformationForecastRight(self):
        self.talk_condition=3
        self.condition=3
        self.randomAct()
        self.passClickTalk()

    # 更新电脑信息显示窗口的内容
    def updateSystemInfo(self):
        # 获取CPU使用率
        cpu_usage = psutil.cpu_percent(interval=1)
        # 获取内存使用率
        memory_usage = psutil.virtual_memory().percent
        # 获取网络传输速度
        network_speed = psutil.net_io_counters().bytes_sent + psutil.net_io_counters().bytes_recv
        network_speed_mb = network_speed / 1024 / (1024 * 60 * 60)

    def showSettingsWindow(self):
        # 创建设置窗口
        self.settings_window = SettingsWindow()
        # 显示设置窗口
        self.settings_window.show()

class SettingsWindow(QMainWindow):
    def __init__(self, parent=None):
        super(SettingsWindow, self).__init__(parent)
        self.initUI()

    def initUI(self):
        # 设置窗口标题
        self.setWindowTitle("设置")
        # 设置窗口大小
        self.resize(2000, 1000)
        # 设置窗口居中显示
        self.center()
        # 设置窗口图标
        self.setWindowIcon(QIcon('settings_icon.jpg'))

        # 创建主窗口的中心部件
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        # 使用水平布局来放置菜单和内容
        layout = QHBoxLayout(central_widget)
        # 创建左侧菜单
        self.menu_list = QListWidget()
        self.menu_list.setFixedWidth(250)  # 设置菜单宽度
        self.menu_list.setIconSize(QSize(48, 48))  # 设置图标尺寸
        self.menu_list.setStyleSheet("""
            QListWidget {
                background-color: #f0f0f0;
                border: 1px solid #ccc;
                font-size: 20px;
                padding: 10px;
            }
            QListWidget::item {
                padding: 10px;
                border-bottom: 1px solid #ccc;
            }
            QListWidget::item:hover {
                background-color: #ddd;
            }
            QListWidget::item:selected {
                background-color: #0078d7;
                color: white;
            }
        """)
        layout.addWidget(self.menu_list)
        # 添加菜单项
        menu_items = ["课表", "时间提醒", "设置城市", "设置健康提醒"]
        for item in menu_items:
            self.menu_list.addItem(QListWidgetItem(QIcon(f'{item.lower()}_icon.jpg'), item))
        # 连接菜单项的点击事件
        self.menu_list.itemClicked.connect(self.on_menu_item_clicked)
        # 创建右侧内容区域
        self.content_stack = QStackedWidget()  # 使用 QStackedWidget 来切换不同的内容页面
        layout.addWidget(self.content_stack)
        # 创建各个内容页面
        self.create_class_schedule_page()
        self.create_time_reminder_page()
        self.create_city_setting_page()
        self.create_health_reminder()

    def create_class_schedule_page(self):
        # 创建课表页面
        page = QWidget()
        layout = QVBoxLayout(page)
        layout.setAlignment(Qt.AlignTop)

        # 添加单双周选择
        self.week = "单周"
        self.week_type_label = QLabel("选择当前周类型：")
        self.week_type_label.setFont(QFont("Roman times", 10, QFont.Bold))
        self.week_type_combobox = QComboBox()
        self.week_type_combobox.addItems(["单周", "双周"])
        self.week_type_combobox.setFont(QFont("Roman times", 12))
        self.week_label = QLabel("选择要更改的课表：")
        self.week_label.setFont(QFont("Roman times", 10, QFont.Bold))
        self.week_type = QComboBox()
        self.week_type.setFont(QFont("Roman times", 12))
        self.week_type.addItems(["单周", "双周"])
        # 直接连接信号到 lambda 表达式，更新 self.week 的值
        self.week_type.currentTextChanged.connect(self.update_week)
        layout.addWidget(self.week_label)
        layout.addWidget(self.week_type)
        layout.addWidget(self.week_type_label)
        layout.addWidget(self.week_type_combobox)

        # 添加开始日期设置
        self.start_date_label = QLabel("设置单周开始日期：")
        self.start_date_label.setFont(QFont("Roman times", 10, QFont.Bold))
        self.start_date_edit = QDateEdit()
        self.start_date_edit.setFont(QFont("Roman times", 12))

        self.start_date_edit.setCalendarPopup(True)
        self.start_date_edit.setDate(QDate.currentDate())
        layout.addWidget(self.start_date_label)
        layout.addWidget(self.start_date_edit)

        # 添加课程表设置
        self.class_schedule_label = QLabel("设置课程表：")
        self.class_schedule_label.setFont(QFont("Roman times", 10, QFont.Bold))
        self.class_schedule_table = QTableWidget()
        self.class_schedule_table.setRowCount(5)
        self.class_schedule_table.setColumnCount(5)
        self.class_schedule_table.setHorizontalHeaderLabels(["周一", "周二", "周三", "周四", "周五"])
        self.class_schedule_table.setVerticalHeaderLabels(["8:00", "9:50", "13:30", "15:20", "18:00"])

        # 设置表格的大小策略，使其随窗口大小调整
        self.class_schedule_table.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.class_schedule_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        self.class_schedule_table.verticalHeader().setSectionResizeMode(QHeaderView.Stretch)

        # 加载当前课表数据
        self.load_class_schedule()

        layout.addWidget(self.class_schedule_label)
        layout.addWidget(self.class_schedule_table)

        # 添加保存按钮
        self.save_class_schedule_button = QPushButton("保存课程表")
        self.save_class_schedule_button.clicked.connect(self.save_class_schedule)
        layout.addWidget(self.save_class_schedule_button)

        self.content_stack.addWidget(page)

    def load_class_schedule(self):
        """从 class_schedule.json 文件中加载课表数据并显示在表格中"""
        try:
            with open('class_schedule.json', 'r', encoding='utf-8') as f:
                schedule = json.load(f)
                # 获取单周和双周的课表数据
                self.singleWeek = schedule.get("单周", {})
                self.doubleWeek = schedule.get("双周", {})
                # 获取当前周类型
                current_type = schedule.get("current_type", "单周")
                self.week_type_combobox.setCurrentText(current_type)
                # 设置开始日期
                start_date = schedule.get("start_date", QDate.currentDate().toString("yyyy-MM-dd"))
                self.start_date_edit.setDate(QDate.fromString(start_date, "yyyy-MM-dd"))
                # 更新表格内容
                self._update_courses()
        except (FileNotFoundError, json.JSONDecodeError):
            # 如果文件不存在或格式错误，初始化空课表
            self.singleWeek = {"周一": [], "周二": [], "周三": [], "周四": [], "周五": []}
            self.doubleWeek = {"周一": [], "周二": [], "周三": [], "周四": [], "周五": []}
            self._update_courses()

    def update_week(self, text):
        # 根据选择的文本更新 self.week
        self.week = text
        # 根据 self.week 的值在周一这一列添加不同的课程名称
        # 打开并读取JSON文件
        with open('class_schedule.json', 'r', encoding='utf-8') as file:
            data = json.load(file)

        # 获取单周和双周的数据
        self.singleWeek = data["单周"]
        self.doubleWeek = data["双周"]

        # 更新表格中的课程信息
        self._update_courses()

    def _update_courses(self):
        """根据当前选择的周类型更新表格内容"""
        week_data = self.singleWeek if self.week_type.currentText() == "单周" else self.doubleWeek
        days_of_week = ["周一", "周二", "周三", "周四", "周五"]

        for day_index, day in enumerate(days_of_week):
            courses = week_data.get(day, [])
            for row, course in enumerate(courses):
                self.class_schedule_table.setItem(row, day_index, QTableWidgetItem(course))

    def save_class_schedule(self):
        """保存课程表设置"""
        schedule = {
            "start_date": self.start_date_edit.date().toString("yyyy-MM-dd"),
            "current_type": self.week_type_combobox.currentText(),
            "上课时间": ["8:00", "9:50", "13:30", "15:20", "18:00"],
            "单周": {},
            "双周": {}
        }

        # 读取单周课程
        if self.week_type.currentText() == "单周":
            single_week_classes = {}
            for col in range(5):
                day_classes = []
                for row in range(5):
                    item = self.class_schedule_table.item(row, col)
                    day_classes.append(item.text() if item else "")
                single_week_classes[self.class_schedule_table.horizontalHeaderItem(col).text()] = day_classes
            schedule["单周"] = single_week_classes
            schedule["双周"] = self.doubleWeek

        # 读取双周课程
        else:
            double_week_classes = {}
            for col in range(5):
                day_classes = []
                for row in range(5):
                    item = self.class_schedule_table.item(row, col)
                    day_classes.append(item.text() if item else "")
                double_week_classes[self.class_schedule_table.horizontalHeaderItem(col).text()] = day_classes
            schedule["双周"] = double_week_classes
            schedule["单周"] = self.singleWeek

        # 保存到文件
        with open('class_schedule.json', 'w', encoding='utf-8') as f:
            json.dump(schedule, f, ensure_ascii=False, indent=4)

        QMessageBox.information(self, "成功", "课程表设置已保存！")

    def center(self):
        # 获取屏幕的几何信息
        screen = QDesktopWidget().screenGeometry()
        # 获取窗口的几何信息
        size = self.geometry()
        # 计算窗口居中的位置
        self.move((screen.width() - size.width()) // 2, (screen.height() - size.height()) // 2)


    def create_time_reminder_page(self):
        # 创建时间提醒页面
        page = QWidget()
        layout = QVBoxLayout(page)
        layout.setAlignment(Qt.AlignTop)
        layout.addWidget(QLabel("这里是时间提醒内容", self))
        self.content_stack.addWidget(page)

    def create_city_setting_page(self):
        # 创建设置城市页面
        page = QWidget()
        layout = QVBoxLayout(page)
        layout.setAlignment(Qt.AlignTop)

        # 创建文本框
        self.city_input = QLineEdit(page)
        self.city_input.setPlaceholderText("请输入城市名称")
        self.city_input.setStyleSheet("""
            QLineEdit {
                padding: 10px;
                font-size: 20px;
                border: 1px solid #ccc;
                border-radius: 5px;
            }
        """)
        # 读取当前城市
        current_city = self.get_current_city()
        self.city_input.setText(current_city)  # 设置文本框的默认值为当前城市
        layout.addWidget(self.city_input)

        # 创建保存按钮
        save_button = QPushButton("保存", page)
        save_button.setStyleSheet("""
            QPushButton {
                background-color: #0078d7;
                color: white;
                padding: 10px;
                font-size: 20px;
                border: none;
                border-radius: 5px;
            }
            QPushButton:hover {
                background-color: #005bb5;
            }
        """)
        save_button.clicked.connect(self.save_city)
        layout.addWidget(save_button)

        self.content_stack.addWidget(page)

    def get_current_city(self):
        # 读取 city.json 文件中的当前城市
        return self._read_json_file("city.json", "所在城市", "")

    def save_city(self):
        # 获取文本框中的城市名称
        new_city = self.city_input.text()
        if new_city:
            self._update_json_file("city.json", "所在城市", new_city)
            QMessageBox.information(self, "成功", "城市设置已保存！")
        else:
            QMessageBox.warning(self, "警告", "城市名称不能为空！")

    def create_health_reminder(self):
        # 创建设置页面
        page = QWidget()
        layout = QVBoxLayout(page)
        layout.setAlignment(Qt.AlignTop)
        layout.setSpacing(20)  # 设置组件之间的间距

        # 创建运动提醒标签
        sport_label = QLabel("运动提醒时间设置（分钟）", page)
        sport_label.setStyleSheet("""
            QLabel {
                font-size: 22px;
                font-weight: bold;
                margin-bottom: 10px;
            }
        """)
        layout.addWidget(sport_label)

        # 创建运动提醒输入框
        self.sport_input = QLineEdit(page)
        self.sport_input.setPlaceholderText("请输入运动提醒时间（分钟）")
        self.sport_input.setStyleSheet("""
            QLineEdit {
                padding: 10px;
                font-size: 20px;
                border: 1px solid #ccc;
                border-radius: 5px;
            }
        """)
        current_sport = self.get_current_sport()
        self.sport_input.setText(current_sport)
        layout.addWidget(self.sport_input)

        # 创建保存运动提醒按钮
        save_sport_button = QPushButton("保存运动提醒", page)
        save_sport_button.setStyleSheet("""
            QPushButton {
                background-color: #0078d7;
                color: white;
                padding: 10px;
                font-size: 20px;
                border: none;
                border-radius: 5px;
            }
            QPushButton:hover {
                background-color: #005bb5;
            }
        """)
        save_sport_button.clicked.connect(self.save_sport_time)
        layout.addWidget(save_sport_button)

        # 创建运动提醒标签
        computer_label = QLabel("电脑健康提醒时间（分钟）", page)
        computer_label.setStyleSheet("""
            QLabel {
                font-size: 22px;
                font-weight: bold;
                margin-bottom: 10px;
            }
        """)
        layout.addWidget(computer_label)

        # 创建电脑健康提醒输入框
        self.computer_input = QLineEdit(page)
        self.computer_input.setPlaceholderText("请输入使用电脑健康提醒时间（分钟）")
        self.computer_input.setStyleSheet("""
            QLineEdit {
                padding: 10px;
                font-size: 20px;
                border: 1px solid #ccc;
                border-radius: 5px;
            }
        """)
        current_computer = self.get_current_computer()
        self.computer_input.setText(current_computer)
        layout.addWidget(self.computer_input)

        # 创建保存电脑健康提醒按钮
        save_computer_button = QPushButton("保存电脑健康提醒", page)
        save_computer_button.setStyleSheet("""
            QPushButton {
                background-color: #0078d7;
                color: white;
                padding: 10px;
                font-size: 20px;
                border: none;
                border-radius: 5px;
            }
            QPushButton:hover {
                background-color: #005bb5;
            }
        """)
        save_computer_button.clicked.connect(self.save_computer_time)
        layout.addWidget(save_computer_button)

        self.content_stack.addWidget(page)

    def get_current_sport(self):
        # 读取 time.json 文件中的运动提醒时间
        return str(self._read_json_file("time.json", "运动时间提醒", 0))

    def get_current_computer(self):
        # 读取 time.json 文件中的电脑健康提醒时间
        return str(self._read_json_file("time.json", "电脑健康时间提醒", 0))

    def save_sport_time(self):
        # 保存运动提醒时间
        self._save_time("运动时间提醒", self.sport_input.text(), "运动时间提醒设置成功！")

    def save_computer_time(self):
        # 保存电脑健康提醒时间
        self._save_time("电脑健康时间提醒", self.computer_input.text(), "电脑健康时间提醒设置成功！")

    def _read_json_file(self, file_name, key, default_value):
        """
        读取 JSON 文件中的指定字段值。
        """
        try:
            with open(file_name, "r", encoding="utf-8") as f:
                data = json.load(f)
                return data.get(key, default_value)
        except (FileNotFoundError, json.JSONDecodeError):
            return default_value

    def _update_json_file(self, file_name, key, value):
        """
        更新 JSON 文件中的指定字段值。
        """
        try:
            with open(file_name, "r", encoding="utf-8") as f:
                data = json.load(f)
        except (FileNotFoundError, json.JSONDecodeError):
            data = {}

        data[key] = value

        with open(file_name, "w", encoding="utf-8") as f:
            json.dump(data, f, ensure_ascii=False, indent=4)

    def _save_time(self, key, input_value, success_message):
        """
        保存时间设置。
        """
        try:
            time_value = int(input_value)
            if time_value <= 0:
                raise ValueError
            self._update_json_file("time.json", key, time_value)
            QMessageBox.information(self, "成功", success_message)
        except ValueError:
            QMessageBox.warning(self, "警告", "请输入有效的正整数！")

    def on_menu_item_clicked(self, item):
        # 根据点击的菜单项切换内容页面
        menu_index = {
            "课表": 0,
            "时间提醒": 1,
            "设置城市": 2,
            "设置健康提醒": 3
        }
        self.content_stack.setCurrentIndex(menu_index.get(item.text(), 0))

    def closeEvent(self, event):
        # 重写 closeEvent 方法，确保关闭设置窗口时不影响主窗口
        event.ignore()  # 忽略关闭事件
        self.hide()  # 隐藏窗口而不是关闭

if __name__ == '__main__':
    # 创建了一个QApplication对象，对象名为app，带两个参数argc,argv
    # 所有的PyQt5应用必须创建一个应用（Application）对象。sys.argv参数是一个来自命令行的参数列表。
    app = QApplication(sys.argv)
    # 窗口组件初始化
    pet = DesktopPet()
    # 1. 进入时间循环；
    # 2. wait，直到响应app可能的输入；
    # 3. QT接收和处理用户及系统交代的事件（消息），并传递到各个窗口；
    # 4. 程序遇到exit()退出时，机会返回exec()的值。
    sys.exit(app.exec_())
